User Setup and Migrations
Authentication with Djoser
Django REST Framework provides basic authentication out of the box, provided with the defaults located in INSTALLED_APPS under settings.py
To build robust applications however, you will need to more functionality than what it offers;
- Registration
- Account Activation (with activation codes sent via email)
- Password Resets (also sent via email)
- Session expiry with JSON Web Tokens (so that you don't just stay logged in forever)
- and so on...
These features are not built in to DRF, and so we'll have to bring in another package or library for this, Djoser
To start, run the command pipenv install djoser djangorestframework-simplejwt
Add djoser and rest_framework_simplejwt to INSTALLED_APPS under settings.py
You should also add the following code blocks to the end of your settings.py
.
REST_FRAMEWORK will change the authentication type
DJOSER provides settings that you will use later on for user registration
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
}
DJOSER = {
'SEND_ACTIVATION_EMAIL': True,
'SEND_CONFIRMATION_EMAIL': True,
'ACTIVATION_URL': 'activation/{uid}/{token}',
}
Add the following to your url_patterns in urls.py
file under the api app
path('', include('djoser.urls')),
path('', include('djoser.urls.jwt'))
Next step, models!
Note!
If you've gotten this far, congratulations! If you're not familiar with basic and intermediate SQL or Python exercises yet, you may have trouble catching up in the following sections. Please consider learning those first or alongside the sections below.
User Model
We've added authentication (Djoser) and so we will need to create our own concept of a user.
Models are the heart of backend development (not just Django!). While you may know what a car or a person is, your backend (Django) and your database have no idea how this should be structured.
A person can have the following
- Name
- Age
- Birthday
Cars can have them too! But you get my point.
Django already provides a default User model, hidden away from sight. We will be overriding and replacing this with our own.
To start, we will need to create a separate app.
In the previous section, we created a simple folder for the api app, this will not work for this step.
Instead, make sure you're inside the Django project directory by doing cd PROJECT_NAME
, in my case, cd djangobackend
We will then create an accounts app. Run the command python manage.py startapp accounts
This will create the accounts app
Note!
The best practice when creating Django apps would be naming them in plural form (Books, Records, Posts)
The Books app can hold
- Books
- Pages
- Chapters
Because of this, there is usually no need to make another app for pages and chapters as mentioned above, unless your app is big enough.
With that out of the way, let's begin creating our User model.
We will be creating our own version of a User based on the default one provided by Django herewith an age and a birthday
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
# Some fields are referenced or copied over from AbstractUser
# first_name, last_name, email, username, and password are among a few of these
birthday = models.DateTimeField(null=True)
age = models.IntegerField(null=True)
@property
def full_name(self):
return f"{self.first_name} {self.last_name}"
If we CTRL + Click on AbstractUser, we can take a deeper look under the hood on Django's default User
By referencing AbstractUser on the User we're creating, we're can skip over creating the other fields a user would have (password, email) and the work that comes with how those work under the hood. This is something you will regularly see with Django and will make developing projects faster.
We'll now need to connect our accounts app and the User model to our existing project
Open the admin.py
file in the accounts app and add the following code block.
from django.contrib import admin
from .models import CustomUser
# Register your models here.
admin.site.register(CustomUser)
This will register the model you just created into the Django admin panel (which you will look into later on).
You should then head over to your settings.py
under the config app and add accounts to INSTALLED_APPS
Point your authentication to your new User model by adding this to settings.py
under the config app
AUTH_USER_MODEL = 'accounts.CustomUser'
Next, you will need to shuffle some things around
Head back to the accounts app and create a urls.py
file. Add the following code block
from django.urls import path, include
urlpatterns = [
path('', include('djoser.urls')),
path('', include('djoser.urls.jwt')),
]
You might notice that this is similar to what we have on the api app, we'll be moving these entries to here.
Now that we have those moved over, remove the entries for djoser.urls and djoser.urls.jwt in urls.py
under the api app
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
]
Instead, replace what we've removed with
path('accounts/', include('accounts.urls')),
Things should look like this after
urls.py
under api app
urls.py
under accounts app
With this, your new accounts app is now connected.
Migrations
Django and Django REST Framework (DRF) serves as an interface between your database (MySQL, PostgreSQL, SQLite) and the internet.
It DOES NOT hold your data. Rather, it serves as the backend to access said data.
This is an important distinction to make especially for starters. Exposing your database without a framework such as Django can allow malicious actors to easily make a mess of everything. Everything Django and DRF provides (authentication, middleware, etc.) serves this purpose.
Carrying on, migrations!
Migrations keep track of what types of kinds of things we wish to store. You previously created a User model (accounts app).
To apply these changes to your database, run the command python manage.py makemigrations
Note!
Make sure you're inside the Django project directory! (e.g. cd PROJECT\_NAME
)
This will create a migration file for your User model, which will instruct Django on how to create it inside your SQL database.
Taking a closer look at the newly created migrations file, you can see the following file in accounts/migrations/0001\_initial.py
The previous command you just ran (python manage.py makemigrations
) just translated your User model (located in accounts/models.py
) into instructions which will then be used to create the SQL statements under the hood (e.g. CREATE TABLE USER (username char, password ...)
)
Migrations are very analogous to sandwiches and burgers in a sense, if you decide to add a grumpy attribute to your User
and run python manage.py makemigrations
again,
This will create a second migration file (0002\_customuser\_grumpy.py
)
When you apply these migrations (which we will do shortly), Django reads each migration file in order, starting off with #1 to create the initial User model, and then to step #2 to add the grumpy field, which under the hood uses SQL Alter (e.g. ALTER USER ADD grumpy boolean
).
Django's migrations will also let you know if you make changes to your models that might break things (e.g. removing an already added field when you have records for that already).
This is something you should ideally understand with Django and how it interfaces with your database under the hood.
Apply Migrations
If you've noticed this error in the previous sections, this is because we haven't applied our migrations yet! With your user schema or template now set up, you should now apply these changes to the database.
Run the command python manage.py migrate
to apply these changes
This will apply your changes to the database, which by default is SQLite**,** the db.sqlite3 file.
With that out of the way, running your Django project (python manage.py runserver 0.0.0.0:8000
) will no longer yield the migration warning.
It's always important to apply your migrations before running your app, otherwise you might run into issues.
In the next section, you will be creating your first (superuser) account to access the Django admin panel.
Up Next: 6 - Django Admin